// app_buttons.c
//
// Purpose: Implements the application-specific button management logic.
// This includes instantiating button objects, configuring their GPIOs
// using the HAL, registering them with the button driver, and creating
// the FreeRTOS task that continuously processes button states.
//
// System Thinking: Connects the generic button driver to the specific hardware buttons.
// Module Thinking: Manages concrete Button_t instances and their initial setup.
// Computational Thinking: Sets up the periodic task that drives button processing.

#include "button.h"
#include "app_buttons.h"
#include "FreeRTOS.h"
#include "task.h"
#include "xil_printf.h"
#include "hw_gpio_defs.h" // For BTN_PIN definitions
#include "hw_gpio_hal.h"  // For HAL_GPIO_SetDirection, HAL_GPIO_SetOutputEnable

// Static instances of Button_t for each physical button.
// These are managed internally by this module, hidden from main.c.
static Button_t s_button_btn0_instance;
static Button_t s_button_btn1_instance;
static Button_t s_button_btn2_instance;
static Button_t s_button_btn3_instance;


/*===================== Button Processing FreeRTOS Task =====================*/
/**
 * @brief FreeRTOS task entry point for processing all registered buttons.
 *        This task periodically calls the button driver's processing function.
 * @param pvParameters Not used in this task.
 *
 * Computational Thinking: A continuous loop implementing the button scanning algorithm.
 * System Thinking: A critical concurrent component that drives the button subsystem.
 */
static void app_button_process_task_entry(void *pvParameters)
{
    (void) pvParameters; // Suppress unused parameter warning

    // Convert scan interval from milliseconds to FreeRTOS ticks.
    const TickType_t xScanDelay = pdMS_TO_TICKS(BUTTON_SCAN_INTERVAL_MS);

    // Inform the user that the task has started.
    xil_printf("Button processing task started with %u ms scan interval.\r\n", (unsigned int)BUTTON_SCAN_INTERVAL_MS);

    while (1)
    {
        // Call the generic button driver to process all registered buttons.
        button_process();
        // Delay the task for the specified scan interval.
        vTaskDelay(xScanDelay);
    }
}

/**
 * @brief Initializes all application-specific buttons.
 */
int app_buttons_init(void)
{
    u8 registered_button_count = 0; // Track successful button registrations

    // Configure and register BTN0
    HAL_GPIO_SetDirection(BTN0_PIN, 0); // 0 for input
    HAL_GPIO_SetOutputEnable(BTN0_PIN, 0); // Disable output enable for input pins
    if (button_register(&s_button_btn0_instance, BTN0_PIN, BUTTON_ACTIVE_LOW, "BTN0") == 0)
    {
        registered_button_count++;
    } else {
        xil_printf("Failed to register BTN0 button.\r\n");
    }

    // Configure and register BTN1
    HAL_GPIO_SetDirection(BTN1_PIN, 0);
    HAL_GPIO_SetOutputEnable(BTN1_PIN, 0);
    if (button_register(&s_button_btn1_instance, BTN1_PIN, BUTTON_ACTIVE_LOW, "BTN1") == 0)
    {
        registered_button_count++;
    } else {
        xil_printf("Failed to register BTN1 button.\r\n");
    }

    // Configure and register BTN2
    HAL_GPIO_SetDirection(BTN2_PIN, 0);
    HAL_GPIO_SetOutputEnable(BTN2_PIN, 0);
    if (button_register(&s_button_btn2_instance, BTN2_PIN, BUTTON_ACTIVE_LOW, "BTN2") == 0)
    {
        registered_button_count++;
    } else {
        xil_printf("Failed to register BTN2 button.\r\n");
    }

    // Configure and register BTN3
    // Note: BTN3 is configured with BUTTON_ACTIVE_HIGH for demonstration diversity.
    HAL_GPIO_SetDirection(BTN3_PIN, 0);
    HAL_GPIO_SetOutputEnable(BTN3_PIN, 0);
    if (button_register(&s_button_btn3_instance, BTN3_PIN, BUTTON_ACTIVE_HIGH, "BTN3") == 0)
    {
        registered_button_count++;
    } else {
        xil_printf("Failed to register BTN3 button.\r\n");
    }

    // xil_printf("Registered %u buttons.\r\n", (unsigned int)registered_button_count);

    // Create the FreeRTOS task for button processing.
    BaseType_t xReturned = xTaskCreate(
        app_button_process_task_entry, // Function that implements the task
        "Button_Scan",                 // Text name for the task
        configMINIMAL_STACK_SIZE + 100,      // Stack size for the task
        NULL,                          // Parameter passed into the task
        tskIDLE_PRIORITY + 2,          // Priority at which the task is created
        NULL                           // Used to pass out the created task's handle
    );

    // Check if task creation was successful.
    if (xReturned != pdPASS)
    {
        xil_printf("Failed to create button processing task!\r\n");
        return -1; // Indicate failure
    }

    return 0; // Indicate success
}
